using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using KinectPG.KinectGameLibrary;
using KinectPG.KinectGameLibrary.Enums;
using Microsoft.Kinect;
using System.Threading;
using KinectPG.LibraryTestGame.Enums;

namespace KinectPG.LibraryTestGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch, background;
        SpriteFont font;
        Texture2D text2d;
        Texture2D fist,fist2,foot,foot2;
        Texture2D backgroundTexture;
        Player player;
        SkeletonManager skeletonManager;
        GestureRecognizer gestureRecognizer;
        Texture2D blank;
        int[][] JointsMap;
        List<Fruit> fruitObjects;
        List<MenuButton> buttons;
        bool gamePaused = false;
        TimeSpan time = new TimeSpan(0, 0, 0);

        #region game config

        private int objectsNumber = 30;

        #endregion

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
            graphics.PreferredBackBufferHeight = 1024;
            graphics.PreferredBackBufferWidth = 1280;
            graphics.ApplyChanges();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            background = new SpriteBatch(GraphicsDevice);
            backgroundTexture = Content.Load<Texture2D>("background");
            font = Content.Load<SpriteFont>("SpriteFont1");
            text2d = Content.Load<Texture2D>(FruitsNames.Orange);
            skeletonManager = new SkeletonManager(TransformSmoothParametersEnum.Smooth, GraphicsDevice);
            gestureRecognizer = new GestureRecognizer(skeletonManager.Limbs);
            // TODO: use this.Content to load your game content here
            blank = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
            blank.SetData(new[] { Color.White });
            JointsMap = new int[23][];
            for (int i = 0; i < 23; i++)
                JointsMap[i] = new int[2];
            for (int i = 0; i < 3; i++)
            {
                JointsMap[i][0] = i;
                JointsMap[i][1] = i + 1;
            }

            for (int i = 4; i < 7; i++)
            {
                JointsMap[i][0] = i;
                JointsMap[i][1] = i + 1;
            }

            for (int i = 8; i < 11; i++)
            {
                JointsMap[i][0] = i;
                JointsMap[i][1] = i + 1;
            }

            for (int i = 12; i < 15; i++)
            {
                JointsMap[i][0] = i;
                JointsMap[i][1] = i + 1;
            }

            for (int i = 16; i < 19; i++)
            {
                JointsMap[i][0] = i;
                JointsMap[i][1] = i + 1;
            }

            JointsMap[19][0] = 2;
            JointsMap[19][1] = 4;

            JointsMap[20][0] = 8;
            JointsMap[20][1] = 2;

            JointsMap[21][0] = 0;
            JointsMap[21][1] = 12;

            JointsMap[22][0] = 0;
            JointsMap[22][1] = 16;

            fruitObjects = new List<Fruit>();
            for (int i = 0; i < objectsNumber; i++)
            {
                fruitObjects.Add(new Fruit(this.spriteBatch, this.GraphicsDevice, Content, 0.2f));
                Thread.Sleep(10);
            }

            //gameObjects.Add(new Fruit(this.spriteBatch, this.GraphicsDevice, Content.Load<Texture2D>("orange"), 0.2f));

            //playerLimbs = new List<PlayerActionLimb>();
            //playerLimbs.Add(new PlayerActionLimb(this.spriteBatch, this.GraphicsDevice, Content.Load<Texture2D>("fist"), 0.5f));
            //playerLimbs.Add(new PlayerActionLimb(this.spriteBatch, this.GraphicsDevice, Content.Load<Texture2D>("fist2"), 0.5f));
            //playerLimbs.Add(new PlayerActionLimb(this.spriteBatch, this.GraphicsDevice, Content.Load<Texture2D>("head"), 0.5f));

            player = new Player(this.spriteBatch, this.GraphicsDevice, this.Content);
            buttons = new List<MenuButton>();
            MenuButton btn = new MenuButton(this.Content, this.GraphicsDevice, this.spriteBatch, "Resume", 200, 500);
            btn.clickActionDelegate = this.ResumeGame;
            buttons.Add(btn);

            btn = new MenuButton(this.Content, this.GraphicsDevice, this.spriteBatch, "Exit", 1000, 500);
            btn.clickActionDelegate = this.Exit;
            buttons.Add(btn);
            //buttons.Add();
            //buttons.Add(new MenuButton(this.Content, this.GraphicsDevice, this.spriteBatch, "Exit", , 100, 100));

        }

        void ResumeGame()
        {
            gamePaused = false;
        }

        void DrawLine(SpriteBatch batch, Texture2D blank,
              float width, Color color, Vector2 point1, Vector2 point2)
        {
            float angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
            float length = Vector2.Distance(point1, point2);

            batch.Draw(blank, point1, null, color,
                       angle, Vector2.Zero, new Vector2(length, width),
                       SpriteEffects.None, 0);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Exit();
                this.gestureRecognizer.Stop();
            }

            // TODO: Add your update logic here
            player.ActiveLimbs[0].PositionVector = new Vector2(skeletonManager.Limbs[(int)JointType.HandRight].ScreenPoint.X / 2, skeletonManager.Limbs[(int)JointType.HandRight].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100);
            player.ActiveLimbs[1].PositionVector = new Vector2(skeletonManager.Limbs[(int)JointType.HandLeft].ScreenPoint.X / 2, skeletonManager.Limbs[(int)JointType.HandLeft].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100);
            player.NonInteractiveLimbs[0].PositionVector = new Vector2(skeletonManager.Limbs[(int)JointType.Head].ScreenPoint.X / 2, skeletonManager.Limbs[(int)JointType.Head].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100);
            //playerLimbs[0].PositionVector = new Vector2(skeletonManager.Limbs[(int)JointType.HandRight].ScreenPoint.X / 2, skeletonManager.Limbs[(int)JointType.HandRight].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100);
            //playerLimbs[1].PositionVector = new Vector2(skeletonManager.Limbs[(int)JointType.HandLeft].ScreenPoint.X / 2, skeletonManager.Limbs[(int)JointType.HandLeft].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100);
            //playerLimbs[2].PositionVector = new Vector2(skeletonManager.Limbs[(int)JointType.Head].ScreenPoint.X / 2, skeletonManager.Limbs[(int)JointType.Head].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100);
            if (gestureRecognizer.BothHandsForward)
                gamePaused = true;

            if (!gamePaused)
            {
                foreach (GameObject go in fruitObjects)
                    go.Update(gameTime);

            }

            time += gameTime.ElapsedGameTime;

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            //GraphicsDevice.Clear(Color.CornflowerBlue);
            background.Begin();
            background.Draw(backgroundTexture, new Rectangle(0, 0, 1280, 1024), Color.AliceBlue);
            background.End();
            spriteBatch.Begin();
            //this.videoFrame = skeletonManager.ColorVideo;
            //if (this.videoFrame != null)
            //    spriteBatch.Draw(this.videoFrame, new Rectangle(0, 0, 640, 480), Color.White);
            for (int i = 0; i < 23; i++)
            {
                if (skeletonManager.Limbs[JointsMap[i][0]].ScreenPoint != null)
                {
                    this.DrawLine(spriteBatch, blank, 2.0f, Color.Red, new Vector2(skeletonManager.Limbs[JointsMap[i][0]].ScreenPoint.X / 2, skeletonManager.Limbs[JointsMap[i][0]].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100), new Vector2(skeletonManager.Limbs[JointsMap[i][1]].ScreenPoint.X / 2, skeletonManager.Limbs[JointsMap[i][1]].ScreenPoint.Y / 2 + (GraphicsDevice.DisplayMode.Height / 2) - 100));
                }
            }

            foreach (PlayerActionLimb pal in player.AllLimbs)
                pal.Draw(gameTime);

            if (!gamePaused)
            {
                foreach (Fruit fruit in fruitObjects)
                    fruit.Draw(gameTime);

                //collision detect here
                foreach (Fruit fruit in fruitObjects)
                {
                    foreach (PlayerActionLimb pal in player.ActiveLimbs)
                    {
                        if (fruit.GetObjectBoundingBox.Intersects(pal.GetObjectBoundingBox))
                        {
                            //TODO: obsluzyc kolizje
                            player.HighScore += fruit.CollisionAction();
                        }
                    }
                }
            }
            else
            {
                foreach (MenuButton btn in buttons)
                {
                    btn.Draw((int)player.ActiveLimbs[0].PositionVector.X, (int)player.ActiveLimbs[0].PositionVector.Y, gameTime);
                }
            }

            this.spriteBatch.DrawString(font, "Fruits hit: " + player.HighScore, new Vector2(10, 50), Color.Orange);
            this.spriteBatch.DrawString(font, "Time: " + time.ToString(), new Vector2(10, 900), Color.Orange);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}
